package com.admin.system.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.handler.PageResultHandler;
import com.admin.model.base.PageResult;
import com.admin.model.dto.UserDto;
import com.admin.model.pojo.*;
import com.admin.system.dao.DeptDao;
import com.admin.system.dao.JobDao;
import com.admin.system.dao.RoleDao;
import com.admin.system.dao.UserDao;
import com.admin.system.security.jwt.SecurityUtils;
import com.admin.system.security.service.UserDetailsServiceImpl;
import com.admin.system.service.UserService;
import com.admin.system.service.mapstruct.UserMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.catalina.security.SecurityUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2021-01-31 19:19:30
 */
@Validated
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
    @Resource
    private UserDao userDao;
    @Resource
    private RoleDao roleDao;
    @Resource
    private DeptDao deptDao;
    @Resource
    private JobDao jobDao;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserMapper userMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void resetPasswordById(Long id) {
        User user = userDao.selectById(id);
        user.setPassword(passwordEncoder.encode("123456"));
        int update = userDao.updateById(user);
        Assert.isTrue(update > 0, "重置密码失败");
        //删除用户缓存
        UserDetailsServiceImpl.clearCacheUser(user.getUsername());
    }

    @Override
    public PageResult queryByDeptId(Long deptId, int pageNum, int pageSize, String orderBy) {
        Page<User> page = PageHelper.startPage(pageNum, pageSize, StrUtil.toUnderlineCase(orderBy)).doSelectPage(() -> {
            userDao.queryByDeptId(deptId);
        });
        return PageResult.builder()
                .total(page.getTotal())
                .rows(userMapper.toDto(page.getResult()))
                .build();
    }

    @Override
    public PageResult queryAll(UserDto userDto, int pageNum, int pageSize, String orderBy) {
        User user = userMapper.toEntity(userDto);
        Page<User> page = PageHelper.startPage(pageNum, pageSize, StrUtil.toUnderlineCase(orderBy)).doSelectPage(()->{
            userDao.queryAll(user);
        });
        return PageResult.builder()
                .total(page.getTotal())
                .rows(userMapper.toDto(page.getResult()))
                .build();
    }

    @Override
    public UserDto queryById(Long id) {
        return userMapper.toDto(userDao.selectById(id));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(UserDto userDto) {
        User user = userMapper.toEntity(userDto);
        //密码为空设置默认密码“123456”，加密密码
        String encode = passwordEncoder.encode(StringUtils.isBlank(user.getPassword()) ? "123456" : user.getPassword());
        user.setPassword(encode);
        int insert = userDao.insert(user);
        Assert.isTrue(insert > 0, "创建失败");
        List<Role> roles = user.getRoles();
        if (!CollectionUtils.isEmpty(roles)) {
            roles.forEach(role -> userDao.authRole(user.getId(), role.getId()));
        }

        List<Dept> depts = user.getDepts();
        if (!CollectionUtils.isEmpty(depts)) {
            depts.forEach(dept -> userDao.authDept(user.getId(), dept.getId()));
        }

        List<Job> jobs = user.getJobs();
        if (!CollectionUtils.isEmpty(jobs)) {
            jobs.forEach(job -> userDao.authJob(user.getId(), job.getId()));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByIds(Set<Long> ids) {
        for (Long id : ids) {
            int delete = userDao.deleteById(id);
            Assert.isTrue(delete > 0, "删除失败");
            Long currentUserId = SecurityUtils.getCurrentUserId();
            Assert.isTrue(!id.equals(currentUserId), "不能删除自己");
            userDao.delAuthJobByUserId(id);
            userDao.delAuthDeptByUserId(id);
            userDao.delAuthRoleByUserId(id);
            //删除用户缓存
            User user = userDao.selectById(id);
            UserDetailsServiceImpl.clearCacheUser(user.getUsername());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateById(UserDto userDto) {
        User user = userMapper.toEntity(userDto);
        int update = userDao.updateById(user);
        Assert.isTrue(update > 0, "更新失败");
        //User newUser = userDao.selectById(user.getId());


        List<Role> roles = user.getRoles();
        if (!CollectionUtils.isEmpty(roles)) {
            //删除用户授权角色
            userDao.delAuthRoleByUserId(user.getId());
            this.authRoles(user.getId(), roles.stream().map(Role::getId).collect(Collectors.toList()));
            //roles.forEach(role -> userDao.authRole(user.getId(), role.getId()));
        }

        List<Dept> depts = user.getDepts();
        if (!CollectionUtils.isEmpty(depts)) {
            //删除用户授权部门
            userDao.delAuthDeptByUserId(user.getId());
            this.authDepts(user.getId(), depts.stream().map(Dept::getId).collect(Collectors.toList()));
            //depts.forEach(dept -> userDao.authDept(user.getId(), dept.getId()));
        }

        List<Job> jobs = user.getJobs();
        if (!CollectionUtils.isEmpty(jobs)) {
            //删除用户授权岗位
            userDao.delAuthJobByUserId(user.getId());
            this.authJobs(user.getId(), jobs.stream().map(Job::getId).collect(Collectors.toList()));
            //jobs.forEach(job -> userDao.authJob(user.getId(), job.getId()));
        }
        //删除用户缓存
        User newUser = userDao.selectById(user.getId());
        UserDetailsServiceImpl.clearCacheUser(newUser.getUsername());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void authRoles(Long userId, List<Long> roleIds) {
        User user = userDao.selectById(userId);
        Assert.notNull(user, "用户不存在");
        roleIds.forEach(roleId -> {
            Role role = roleDao.selectById(roleId);
            Assert.notNull(role, "角色不存在");
            int authUpdate = userDao.authRole(userId, roleId);
            Assert.isTrue(authUpdate > 0, "《{}》 角色授权失败", role.getName());
        });
        //删除用户缓存
        UserDetailsServiceImpl.clearCacheUser(user.getUsername());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void authDepts(Long userId, List<Long> deptIds) {
        User user = userDao.selectById(userId);
        Assert.notNull(user, "用户不存在");
        deptIds.forEach(deptId -> {
            Dept dept = deptDao.selectById(deptId);
            Assert.notNull(dept, "部门不存在");
            Assert.isTrue(dept.getEnabled(), "《{}》 部门已被禁用无法授权", dept.getName());
            int authUpdate = userDao.authDept(userId, deptId);
            Assert.isTrue(authUpdate > 0, "《{}》 部门授权失败", dept.getName());
        });
        //删除用户缓存
        UserDetailsServiceImpl.clearCacheUser(user.getUsername());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void authJobs(Long userId, List<Long> jobIds) {
        User user = userDao.selectById(userId);
        Assert.notNull(user, "用户不存在");
        jobIds.forEach(jobId -> {
            Job job = jobDao.selectById(jobId);
            Assert.notNull(job, "岗位不存在");
            Assert.isTrue(job.getEnabled(), "《{}》 岗位已被禁用，无法授权", job.getName());
            int authUpdate = userDao.authJob(userId, jobId);
            Assert.isTrue(authUpdate > 0, "《{}》 岗位授权失败", job.getName());
        });
        //删除用户缓存
        UserDetailsServiceImpl.clearCacheUser(user.getUsername());
    }

    @Override
    public List<Menu> queryMenusByUserIdAndTypeNot(Long userId, int type) {
        User user = userDao.selectById(userId);
        List<Role> roles = user.getRoles();
        //获得所有角色id
        List<Long> rolesIds = roles.stream().map(Role::getId).collect(Collectors.toList());
        return roleDao.queryMenuByRoleIdsAndTypeNot(rolesIds, type);
    }
}